package sch.frog.behavioral.interpreter.calculator;

import sch.frog.behavioral.interpreter.calculator.expression.Expression;
import sch.frog.behavioral.interpreter.calculator.expression.end.NumberExpression;
import sch.frog.behavioral.interpreter.calculator.expression.mid.AddExpression;
import sch.frog.behavioral.interpreter.calculator.expression.mid.DivExpression;
import sch.frog.behavioral.interpreter.calculator.expression.mid.MultExpression;
import sch.frog.behavioral.interpreter.calculator.expression.mid.SubExpression;

public class Context {

    private String expression;

    public Context(String expression){
        this.expression = expression.replaceAll(" ", "");
    }

    private static class ParseResult{
        private int endIndex;
        private Expression expression;
    }

    private Expression explain(){
        char[] chars = expression.toCharArray();

        AddExpression initExp = new AddExpression();
        initExp.setLeft(new NumberExpression("0"));
        Expression root = initExp;

        for(int i = 0; i < chars.length; i++){
            ParseResult result = parseExpression(i, chars);
            if(result.expression == null) continue;

            root = root.assembleTree(result.expression);

            if(root == null){
                throw new IllegalStateException("tree root lost.");
            }

            i = result.endIndex;
        }

        return root;
    }

    private ParseResult parseExpression(int start, char[] expression){
        ParseResult result = new ParseResult();

        int end = start;

        NumberExpression number = null;
        Expression exp = null;

        for(; end < expression.length; end++){
            char ch = expression[end];
            if(isNumber(ch) || isDot(ch)){
                if(exp != null) break;

                if(number == null){
                    number = new NumberExpression();
                }

                number.assemble(ch);
                result.expression = number;
            }else{
                if(number != null) break;

                exp = getExpresion(ch);
                result.expression = exp;
            }

        }

        result.endIndex = end - 1;

        return result;
    }

    private Expression getExpresion(char symbol){
        Expression exp = null;
        switch (symbol){
            case '+':
                exp = new AddExpression();
                break;
            case '-':
                exp = new SubExpression();
                break;
            case '*':
                exp = new MultExpression();
                break;
            case '/':
                exp = new DivExpression();
                break;
        }
        return exp;
    }


    public double calculate(){
        return explain().interpret();
    }

    private boolean isNumber(char ch){
        return ch >= '0' && ch <= '9';
    }

    private boolean isDot(char ch){
        return ch == '.';
    }

}
